Skip to content

feat: 集成 AstrBot SDK vendored runtime 与 bridge 运行时#6810

Open
whatevertogo wants to merge 512 commits intoAstrBotDevs:masterfrom
whatevertogo:feat/sdk-integration
Open

feat: 集成 AstrBot SDK vendored runtime 与 bridge 运行时#6810
whatevertogo wants to merge 512 commits intoAstrBotDevs:masterfrom
whatevertogo:feat/sdk-integration

Conversation

@whatevertogo
Copy link
Copy Markdown
Contributor

@whatevertogo whatevertogo commented Mar 22, 2026

动机 / Motivation

这个 PR 的目标,不是简单"把一个新 SDK 目录拷进主仓库",而是把 AstrBot SDK v4 的运行时能力 以一种可以在主仓库长期维护、逐步落地、并且不破坏旧插件生态的方式接入 AstrBot。

与其说它是 SDK,不如说它是为了新旧插件都兼容的新插件扩展平台。

要解决的核心问题有 4 类:

  1. 插件运行边界不清晰
    旧插件路径与主进程深度耦合,插件直接共享宿主进程内对象,插件异常、运行时污染、依赖冲突都更容易放大到整个系统。

  2. 插件开发接口过于依赖宿主内部实现
    旧接口里很多能力是"直接拿宿主对象调用"的风格,虽然能用,但边界不稳定、类型约束弱、难以做清晰的能力声明,也不利于长期演进。

  3. 主仓库和 SDK 仓库的职责边界需要明确
    独立的 astrbot-sdk 仓库需要作为 SDK 的 source of truth 持续演进;AstrBot 主仓库需要的是一个可消费、可同步、可测试的 vendored 运行时快照,而不是把整个 SDK 源仓库原样搬进来。

  4. 迁移必须渐进,不能推翻现有插件体系
    AstrBot 现有大量逻辑仍然基于 legacy Star 插件体系。SDK 的接入必须保证:

    • 旧插件继续按旧路径工作
    • 新插件可以走 SDK 路径
    • 两者在同一条主消息流水线、Dashboard、平台命令注册体系里共存

因此,这个 PR 的真实定位是:

  • 在 AstrBot 主仓库中 vendoring 一份 SDK 运行时快照
  • 在主仓库中新增一层 sdk_bridge 宿主桥接层
  • 让 SDK 插件能够通过协议和 capability 调用 AstrBot Core
  • 同时保持 legacy 路径继续可用,形成一个 增量迁移架构

变更规模 / Change Statistics

指标 数值
变更文件 260
新增行数 73,102
删除行数 522
提交数 510

按模块统计:

模块 文件数 说明
astrbot-sdk/ 107 SDK vendored snapshot(含 runtime、clients、CLI、testing、memory backend 等)
astrbot/core/sdk_bridge/ 18 宿主桥接层(plugin_bridge、capability_bridge + 13 个 mixin、trigger_converter、dispatch_engine 等)
tests/ 28+ SDK 集成测试、单元测试(test_sdk/unit/ 下 26 个测试文件)、兼容性测试
astrbot/core/ 多个 core_lifecycle 等核心模块增强
astrbot/dashboard/ 多个 命令/工具/插件/配置/技能路由扩展
astrbot/core/pipeline/ 多个 流水线 stage 接入 SDK handler 分发
astrbot/core/platform/sources/ 3 新增 weixin_oc 适配器(weixin_oc_adapter.py、weixin_oc_client.py、weixin_oc_event.py)
scripts/ 2 SDK 同步脚本(sync-sdk.sh / sync-sdk.ps1)

这次 PR 实际做了什么

1. 在主仓库中引入 astrbot-sdk/ 的 vendored snapshot

这个 PR 在主仓库下新增了 astrbot-sdk/ 目录,但这里必须明确:

  • 这里的 astrbot-sdk/给 AstrBot 主仓库消费的 vendored subtree snapshot
  • 它不是独立 astrbot-sdk 源仓库的完整镜像
  • 它保留的是 AstrBot 运行时真正需要的 SDK 包布局和最小配套文件

这里保留的主要内容包括:

  • src/astrbot_sdk/:SDK 运行时包主体
  • pyproject.toml:让主仓库可以按本地 path dependency 使用 SDK(构建后端使用 hatchling
  • README.md / VENDORED.md / LICENSE:说明 vendoring 约定与快照边界
  • templates/project_notes/AGENTS.md / CLAUDE.md:因为 astr init 仍然会生成这些模板
  • testing.py_testing_support.py_internal/testing_support.py 等最小测试辅助:因为主仓库与模板仍然依赖这些约定

同时,很多内容是 刻意不 vendoring 进主仓库的

  • SDK 源仓库完整 docs
  • 大量仅用于 SDK 仓库自身演进的测试与开发元数据

这样设计的原因是:

  1. 主仓库要消费稳定快照,不是承载 SDK 全量研发现场
    AstrBot 主仓库关注的是"可运行、可集成、可回归"的 SDK 版本,而不是承接 SDK 仓库的所有开发噪音。

  2. source of truth 必须单一
    SDK 行为、文档、测试体系的第一来源仍然应该是独立 astrbot-sdk 仓库。主仓库里的 astrbot-sdk/ 只是同步产物,不应该再被误解为主要开发位置。

  3. 便于后续同步与审查
    scripts/sync-sdk.ps1 / scripts/sync-sdk.sh 明确要求:

    • 先更新独立 SDK 仓库
    • 再通过 subtree 同步 vendor branch 到主仓库
      这保证了变更路径清晰,减少"主仓库偷偷改 SDK vendored 文件"的维护风险。

2. 把 SDK 的运行时模型正式接入 AstrBot 主仓库

主仓库引入的不只是一个 Python package,而是一整套 SDK 运行时入口:

  • protocol/:协议消息模型(messages.pydescriptors.py_builtin_schemas.py)与描述符
  • runtime/:loader / peer / transport / supervisor / worker / handler_dispatcher / capability_router / environment_groups 等运行时骨架
  • clients/:17 个客户端模块,覆盖 ctx.llmctx.memoryctx.dbctx.platformctx.provider 等高层客户端
  • decorators.py:声明式 handler/capability 注册入口(20+ 装饰器,涵盖 on_command、on_message、on_event、on_schedule、on_provider_change、validate_config、http_api、mcp_server、register_skill、background_task 等)
  • context.py / events.py / message/*:插件作者直接面对的主要 API

SDK 本身的设计是比较清晰的一条链路:

插件作者 API
  -> Context / Decorators / MessageEvent
  -> 各种 typed clients
  -> CapabilityProxy / Peer
  -> Protocol messages
  -> 宿主侧 capability router

也就是说,SDK 不是让插件"直接摸宿主对象",而是让插件通过 显式能力调用 与宿主通信。

这套设计的核心思想有三点:

  1. 协议优先(protocol-first)
    先定义清楚消息模型、调用边界、错误结构,再谈功能。

  2. 能力优先(capability-first)
    宿主暴露什么能力,要通过 capability 名称和 payload schema 明确表达,而不是让插件到处拿宿主内部对象直接调用。

  3. 声明式优先(descriptor-first)
    handler、trigger、capability 都先变成可序列化描述符,再进入运行时分发。这让跨进程、热重载、命令面板、平台命令注册这些事情都更可控。

3. V4 协议设计

SDK 使用自定义的 v4 JSON 协议(而非 JSON-RPC)进行内部通信。这个选择经过项目成员充分讨论,定位如下:

为什么内部使用 v4 而不是 JSON-RPC:

  • 把 AstrBot 的领域对象直接放进协议层(SessionRefCapabilityDescriptor、流式能力声明、取消能力声明),不需要像 JSON-RPC 那样把运行时语义塞进 params
  • 原生支持 AstrBot 的握手需求:初始化阶段交换 handlers、provided_capabilities、协议版本、元数据
  • 流式调用做成明确生命周期(started/delta/completed/failed 四段式),对 LLM 输出、长任务更清晰
  • 取消建模为一等协议消息 CancelMessage,不是额外约定
  • 调用者身份(caller_plugin_id)和请求作用域(_request_scope_id)放进运行时链路,对权限、隔离、审计关键
  • 稳定的领域错误模型(capability_not_foundprotocol_version_mismatchcapability_timeout 等显式错误码)

v4 差于 JSON-RPC 的地方(已知的 trade-off):

  • 通用性差,基本是 AstrBot 私有协议
  • 生态差,没有现成的客户端/调试器/跨语言支持
  • batch 处理尚不如 JSON-RPC 成熟
  • 协议演进成本更高

结论:v4 负责 AstrBot 内核语义,JSON-RPC 负责外部通用互联(如 MCP 接入仍然走 JSON-RPC 2.0)。

4. 插件加载与命名空间隔离

SDK 的插件加载机制使用现代 Python 隔离方案:

  • _PluginScopedMetaPathFinder:注册到 sys.meta_path,拦截插件模块导入
  • _plugin_scoped_import:替换 builtins.__import__,实现插件间导入隔离
  • 每个插件代码被加载到 astrbot_ext_{plugin_id} 独立命名空间中
  • 通过 _ensure_plugin_package() 设置模块 __path__,注册到 sys.modules

这与传统的 sys.path.insert 方式完全不同,避免了插件间的模块名冲突和全局命名空间污染。

5. 虚拟环境分组

SDK runtime 包含 environment_groups.py,实现依赖兼容性分组:

发现插件 → 按依赖兼容性分组 → 为每组创建 venv → 每个插件启动独立 Worker
   ↓            ↓                    ↓              ↓
 5个插件    用uv测试自动分组     创建2-3个venv     5个Worker进程
  • 兼容的插件共享虚拟环境(节省资源)
  • 冲突的插件自动分配到不同环境
  • 插件更新引入新依赖冲突时,当前组环境会被重建,该插件被重新分配
  • 每个插件仍然有独立的 Worker 进程(保持隔离)

6. SDK CLI 工具链

SDK 包含完整的命令行工具(astr 命令),为插件开发者提供端到端的工作流支持:

子命令 功能
astr init 创建新插件骨架,生成 plugin.yaml、main.py、README.md、测试模板;支持 --agents claude,codex 自动生成 AI 编程助手 skill 模板
astr validate 校验 plugin.yaml 清单、导入路径、handler 发现是否正常
astr build 将插件打包为 .zip 发布包,自动排除 .git、pycache 等无关文件
astr dev --local 本地开发模式,支持 --watch 文件变更热重载、--interactive 交互调试
astr run 启动插件 supervisor 进程,通过 stdio 与 AstrBot 核心通信
astr serve-worker 启动 WebSocket Worker,支持 TLS
astr worker 内部命令,由 supervisor 调用以启动单个插件 worker 进程

7. 插件持久化记忆系统

SDK 内置 PluginMemoryBackend(1,515 行),提供插件级别的持久化键值记忆后端:

  • 存储引擎:SQLite(WAL 模式),自动管理过期条目清理
  • 全文搜索:FTS5 虚拟表,支持 Unicode tokenizer
  • 向量搜索:可选 FAISS 集成(IndexFlatIP + IndexIDMap2),无 FAISS 时退化为精确余弦相似度
  • 混合搜索:keyword + vector 混合评分(0.65 × vector + 0.35 × keyword + 0.05 bonus)
  • TTL 支持save_with_ttl() 支持带过期时间的记忆条目
  • 命名空间:层级命名空间隔离,支持 include_descendants 递归查询
  • 嵌入管理:自动检测缺失嵌入、按需批量计算、脏标记驱动的增量索引构建

8. SDK 客户端面(Capability Surface)

SDK 通过 Context 暴露 17+ 类型化客户端,每个客户端背后是 capability proxy:

客户端 能力域 关键方法
LLMClient LLM 调用 chat, chat_raw, stream_chat
MemoryClient 记忆管理 search, save, get, delete, list_keys
DBClient 键值存储 get, set, delete, list, get_many, set_many
PlatformClient 平台消息 send, send_stream, get_member_info, get_group_member_list
ProviderClient Provider 代理 chat_for_provider, get_llm_profile
ProviderManagerClient Provider 管理 list_providers, get_provider
PersonaManagerClient 人格管理 list, create, update, delete
ConversationManagerClient 对话管理 list, create, update, delete, set_active
KnowledgeBaseManagerClient 知识库管理 list, create, update, delete, upload, retrieve
MessageHistoryManagerClient 消息历史 list, get_page
MCPManagerClient MCP 管理 list_servers, register_global_server, enable_server, session_call
PermissionClient 权限校验 check
PermissionManagerClient 权限管理 list, add, remove
SkillClient 技能注册 register_skill, unregister_skill
HTTPClient Web API register_api, unregister_api
MetadataClient 插件元数据 get_plugin_config, get_plugin_metadata
FileServiceClient 文件服务 register_file, handle_file
SessionServiceManager 会话服务 会话级 MCP/Provider 管理

9. SDK 测试基础设施

SDK 提供完善的测试辅助(astrbot_sdk.testing),支持插件作者编写单元测试和集成测试:

  • MockContext:完整 mock 的 Context,内置 InMemoryDB、InMemoryMemory、MockCapabilityRouter
  • MockMessageEvent:可配置 user_id / group_id / platform / session 的 mock 事件
  • MockLLMClient:支持预设响应(mock_response / mock_stream_response
  • MockPlatformClient:记录发送历史,支持 assert_sent 断言
  • PluginHarness:从 plugin.yaml 加载插件并执行完整 dispatch 流程
  • StdoutPlatformSink:将平台输出捕获到内存或 stdout

SDK 为什么这样设计

1. 为什么要做 Worker / Supervisor 运行时边界

SDK 的核心架构是把插件执行从主进程逻辑里抽出来,形成更明确的执行边界:

  • Supervisor 管理 Worker 生命周期
  • WorkerSession 代表一个被宿主管理的插件运行单元
  • Peer + Transport 负责协议收发
  • HandlerDispatcher / CapabilityDispatcher 负责把协议调用分发到真实 Python 对象

这样做的原因是:

  1. 隔离故障域
    插件执行失败、卡死、局部污染时,不必直接把主进程也拖下水。

  2. 隔离依赖与环境
    SDK 运行时天然更适合做环境分组、虚拟环境规划和后续多运行边界扩展。

  3. 让宿主和插件关系从"对象耦合"变成"协议耦合"
    这会让系统更难写一点,但长期维护成本更低,因为边界明确以后,兼容性和演进策略才可控。

2. 为什么是 Capability Router,而不是直接暴露宿主 API

Context 下的 llm / memory / db / platform / provider / permission / kb / mcp 等客户端,本质上都是 capability 的 typed facade。

这样做的好处是:

  1. 调用边界稳定
    插件只需要知道 capability 名称和参数,不需要知道宿主内部对象结构。

  2. 更适合做 schema 验证与错误治理
    Capability 本身就是"一个命名的、结构化的远程调用点",天然适合做 JSON Schema、错误码、重试语义和 docs_url。

  3. 便于宿主分层实现
    主仓库里真正干活的代码仍然可以分散在 ProviderManager、PlatformManager、ConversationManager、DB、KB 等各处,但对 SDK 来说只看见统一 capability surface。

3. 为什么 handler / trigger 要走描述符,而不是靠反射硬猜

HandlerDescriptorCommandTriggerMessageTriggerEventTriggerScheduleTrigger 这一层是 SDK 的一个重要设计点。

它解决的是:

  • 插件注册了什么 handler
  • 这个 handler 由什么触发
  • 它属于命令、消息、系统事件还是定时任务
  • 它需要什么权限、优先级、过滤器、参数模型

如果没有这一层,宿主要做的事情会很混乱:

  • Dashboard 很难正确列命令
  • 平台原生命令注册很难同步
  • 热重载后很难稳定恢复状态
  • 跨进程后宿主几乎拿不到完整元信息

描述符层的意义,本质上是把"运行时行为"先降维成"静态声明",这样宿主侧才有机会在真正执行前做规划、注册、展示和校验。


为什么 AstrBot 主仓库还需要一层 sdk_bridge

如果 SDK 已经有 protocol、peer、capability_router,为什么主仓库还要额外实现 astrbot/core/sdk_bridge/

因为 SDK 是通用插件运行时,AstrBot Core 则是一个已经存在多年、已有完整 legacy 体系、已有平台适配器、已有消息流水线和 Dashboard 的具体宿主。两者之间不可能无缝直接拼上,必须有一层宿主适配桥。

sdk_bridge 做的事情,本质上是把:

  • AstrBot Core 的内部对象与流程
  • SDK runtime 所要求的协议与能力边界

做一次明确的对接。

可以把它理解为:

  • SDK 决定"插件应该怎么描述自己、怎么调用宿主、怎么收消息、怎么返回结果"
  • sdk_bridge 决定"在 AstrBot 这个具体宿主里,这些事情到底接到哪里去、怎么兼容现有流水线"

sdk_bridge 的设计与职责

1. SdkPluginBridge:宿主侧总入口(2,923 行)

astrbot/core/sdk_bridge/plugin_bridge.py 是这一层的核心。

它承担了几类关键职责:

  1. 插件发现与运行管理

    • 调用 SDK runtime loader 发现插件
    • 启动/维护 WorkerSession
    • 处理 reload、turn on/off、失败重试、运行状态切换
  2. handler 匹配与分发

    • 收集 SDK 插件暴露出来的 handler 描述符
    • 在宿主消息到来时做 trigger matching
    • 把命中的 handler 调到对应 Worker 执行
  3. 请求级状态管理

    • 通过 _RequestOverlayState 跟踪单次消息分发的 overlay 状态
    • 保存 SDK handler 返回的 sent_message / stop / call_llm
    • 管理 SDK-local extras、effective result、handler whitelist 等请求级数据
  4. 宿主侧面板与管理接口

    • 给 Dashboard 提供命令、工具、插件元信息、配置 schema
    • 给平台适配器提供 native command candidates
    • 接 SDK HTTP API 路由分发
  5. 宿主事件桥接

    • 分发 message event
    • 分发 system event,比如 decorating_resultagent_beginagent_done
    • 处理 event/result payload 与宿主消息模型之间的转换

2. CoreCapabilityBridge:把 AstrBot Core 能力整理成 SDK capability surface

astrbot/core/sdk_bridge/capability_bridge.py 是一个 70 行的组合类,通过多重继承从 13 个 Mixin 类组合所有能力。

当前拆分出的能力组包括(对应 sdk_bridge/capabilities/ 下的 mixin 文件):

Mixin 职责
_host.py 宿主基础信息与插件运行环境
basic.py 基础 CRUD 与状态查询
llm.py LLM 聊天、流式、结构化调用
provider.py Provider 管理
platform.py 平台消息发送与成员管理
session.py 会话级状态与服务管理
persona.py 人格管理
conversation.py 对话管理
knowledgebase.py / kb.py 知识库管理
message_history.py 消息历史查询
permission.py 权限校验与管理
mcp.py MCP 服务器注册与调用
skill.py 技能注册与同步
system.py 系统级文件、路径、token、日志等能力

3. 其他桥接组件

组件 职责
TriggerConverter 把 SDK trigger/filter/permission 规则映射到 AstrBot 当前消息事件模型
event_payload.py 把宿主 AstrMessageEvent 关键信息抽成 InboundEventSnapshot,做 JSON-safe 清洗
dispatch_engine.py SDK handler 分发引擎
lifecycle_manager.py SDK 插件生命周期管理
mcp_manager.py SDK 侧 MCP 服务管理
registry_manager.py SDK handler/capability 注册管理
request_runtime.py 请求级运行时状态
runtime_store.py 运行时数据存储

4. _RequestOverlayState:请求覆盖层

这是 bridge 设计里最容易被忽略、但实际上非常关键的部分。

AstrBot 原有流水线不是为"SDK 插件在另一套 runtime 里执行,并返回 stop/call_llm/result 覆盖行为"而设计的。为了在不重写整个流水线的前提下把 SDK 接进去,必须引入一层 请求级 overlay state

它解决的核心问题是:

  1. SDK handler 返回的结果要能影响宿主后续流水线
  2. 这些影响必须是"本次请求级"的,而不是全局状态
  3. 宿主现有 stage 必须能读取"effective result"而不是只读 event.get_result()

这是一个很典型的增量架构设计:不硬推翻旧流水线,不把 SDK 行为偷偷塞进全局变量,而是在请求粒度建立一个明确的覆盖层。


这个 bridge 是如何嵌入 AstrBot 现有生命周期的

1. Core Lifecycle 接入

astrbot/core/core_lifecycle.py 里,这个 PR 增加了:

  • 初始化 SdkPluginBridgefrom astrbot.core.sdk_bridge import SdkPluginBridge
  • 把 bridge 注入 star_context
  • 在核心启动阶段 start()

2. Pipeline 接入

改动点主要在 pipeline 各 stage,核心改动是让 pipeline 在关键节点具备以下能力:

  1. 在 legacy handlers 执行后,继续调度 SDK handlers
  2. 如果 SDK handler 已经发送消息或终止传播,宿主要知道
  3. 如果 SDK handler 改写了 result,后续 stage 应该读取 effective result
  4. call_llm 的最终决策不能再只看 legacy event 状态,还要看 SDK overlay 决策
  5. decorating_result 这类宿主事件也需要反向派发给 SDK

设计重点是 共存而非替换——legacy handler 路径继续跑,SDK 路径在合适阶段接入,最终结果由 bridge 的请求级状态协调。

3. Dashboard 接入

Dashboard 相关改动遵循以下设计策略:

  1. SDK 命令标记为只读(source of truth 在插件描述符)
  2. SDK tools 纳入统一工具面板,支持激活/停用
  3. 配置 schema 通过 bridge 获取,不复制配置逻辑

4. 平台原生命令接入

在 Telegram / Discord 适配器里,增加了从 bridge 读取 native command candidates 的逻辑。同一份元数据既能驱动运行时触发,也能驱动 Dashboard 展示,还能驱动平台命令注册。

5. 新增 weixin_oc 平台适配器

新增企业微信(WeCom Open Platform)适配器,包含 adapter、client、event 三个模块。


测试覆盖

本 PR 新增大量测试代码,分布在以下区域:

测试目录/文件 覆盖范围
tests/test_sdk/unit/test_sdk_bridge_extended.py Bridge 扩展测试
tests/test_sdk/unit/test_sdk_bridge_runtime_capabilities.py Bridge 运行时能力测试
tests/test_sdk/unit/test_sdk_clients_doc_roundtrip.py 客户端文档 roundtrip 测试
tests/test_sdk/unit/test_sdk_context_api_doc_behavior.py Context API 行为测试
tests/test_sdk/unit/test_sdk_core_bridge_db_capabilities.py DB capability 测试
tests/test_sdk/unit/test_sdk_core_bridge_http_capabilities.py HTTP capability 测试
tests/test_sdk/unit/test_sdk_core_bridge_memory_capabilities.py Memory capability 测试
tests/test_sdk/unit/test_sdk_core_bridge_permission_capabilities.py Permission capability 测试
tests/test_sdk/unit/test_sdk_decorator_capability_roundtrip.py 装饰器 capability 测试
tests/test_sdk/unit/test_sdk_dispatch_engine.py 分发引擎测试
tests/test_sdk/unit/test_sdk_dynamic_registration_plugin_flow.py 动态注册流程测试
tests/test_sdk/unit/test_sdk_error_handling_doc_behavior.py 错误处理行为测试
tests/test_sdk/unit/test_sdk_event_and_components_behavior.py 事件和组件行为测试
tests/test_sdk/unit/test_sdk_legacy_process_stage_compat.py Legacy 流水线兼容性测试
tests/test_sdk/unit/test_sdk_llm_capabilities.py LLM 能力测试
tests/test_sdk/unit/test_sdk_loader_import_isolation.py 插件加载隔离测试
tests/test_sdk/unit/test_sdk_mcp_capabilities.py MCP 能力测试
tests/test_sdk/unit/test_sdk_message_history_managers.py 消息历史管理测试
tests/test_sdk/unit/test_sdk_message_objects.py 消息对象测试
tests/test_sdk/unit/test_sdk_native_command_registration.py 原生命令注册测试
tests/test_sdk/unit/test_sdk_persona_conversation_kb_managers.py 人格/对话/KB 管理测试
tests/test_sdk/unit/test_sdk_plugin_config_bridge.py 插件配置桥接测试
tests/test_sdk/unit/test_sdk_provider_platform_management.py Provider/平台管理测试
tests/test_sdk/unit/test_sdk_provider_tool_platform_capabilities.py Provider 工具能力测试
tests/test_sdk/unit/test_sdk_transport.py Transport 层测试
tests/test_sdk/unit/test_sdk_vnext_author_experience.py 插件开发者体验测试
tests/test_sdk/unit/*context_api_* 各客户端 API roundtrip 测试(db、files、http、memory、metadata、platform、provider、session、skills)

兼容性与迁移结论

Breaking Changes

  • 这个 PR 不以破坏 legacy Star 插件兼容性为目标

预期兼容策略是:

  • legacy Star 插件继续走现有宿主逻辑
  • SDK 插件走新的 runtime + bridge 逻辑
  • 两者共用同一个 AstrBot Core 生命周期与主消息流水线

这是一个 宿主能力扩展与架构铺路,而不是激进替换。新架构代码全部放在 _internal 包内,不会与现有架构产生冲突。

从迁移角度看,它建立的是一个可逐步迁移的双轨体系:

  • 老插件不必立刻重写
  • 新插件可以开始按 SDK v4 的方式开发
  • 宿主逐步把新能力纳入 capability surface

已知待解决事项

  • 批量请求:v4 协议的批量处理能力尚未完善(但是使用前景不高)

验证方式 / Verification

# AstrBot 主仓库侧 SDK 集成与兼容性测试
uv run pytest tests/test_sdk/ -q
uv run pytest tests/test_dashboard.py tests/test_db_backward_compat.py tests/test_computer_config.py -q
uv run pytest tests/test_plugin_manager.py tests/test_platform_register.py -q

# 可选:独立 astrbot-sdk 源仓库侧回归
cd ../astrbot-sdk
uv run pytest tests/test_runtime_peer.py tests/test_mcp_runtime.py tests/test_sync_vendor_script.py -q

Checklist / 检查清单

  • 已明确 astrbot-sdk/ 在主仓库中是 vendored snapshot,而不是完整 SDK 源仓库
  • 已解释 SDK 采用 protocol-first / capability-first / descriptor-first 的设计原因
  • 已解释 sdk_bridge 在 AstrBot 宿主中的职责、边界和存在必要性
  • 已说明当前集成策略是与 legacy Star 共存,而不是直接替换旧体系
  • 已补充变更规模统计(260 文件、73,102 行新增、510 commits)
  • 已补充 SDK CLI 工具链说明(init/validate/build/dev/run/serve-worker/worker)
  • 已补充插件持久化记忆系统说明(SQLite + FTS5 + FAISS)
  • 已补充 SDK 客户端面详细列表(17+ 类型化客户端)
  • 已补充测试覆盖范围说明(26+ 单元测试文件)
  • 已补充 v4 协议设计理由(为什么不用 JSON-RPC)
  • 已补充插件加载隔离机制(MetaPathFinder + astrbot_ext_ 命名空间)
  • 已补充虚拟环境分组机制(environment_groups)
  • 已补充新平台适配器(weixin_oc)
  • 已补充构建系统(hatchling)
  • 已修正 plugin_bridge.py 行数为实际 2,923 行
  • 已补充 sdk_bridge 完整文件列表(含 dispatch_engine、lifecycle_manager、mcp_manager 等)
  • 已标注已知待解决事项(MD5 安全审查、批量请求)

whatevertogo and others added 30 commits March 20, 2026 18:16
- Implemented `validate_plugin_id` to ensure safe plugin identifiers.
- Added `resolve_plugin_data_dir` to resolve plugin data directories securely.
- Updated memory and system capabilities to utilize new plugin ID validation.
- Refactored session waiter management to simplify plugin ID handling.
- Enhanced tests for plugin ID validation and data directory resolution.
feat(memory): 增强内存功能并修复测试与注入问题
…tion-review

fix(runtime): resolve issue AstrBotDevs#24 review regressions and add coverage
- Moved message result and session classes to internal modules while preserving legacy import paths for compatibility.
- Updated imports across the SDK to reflect the new internal structure.
- Enhanced session waiter management to support multiple plugins and improve error handling.
- Added tests to ensure LLM tool registration and session waiter functionality align with dispatcher expectations.
- Cleaned up code and improved documentation for clarity and maintainability.
# Conflicts:
#	src/astrbot_sdk/context.py
#	src/astrbot_sdk/runtime/handler_dispatcher.py
#	src/astrbot_sdk/session_waiter.py
#	src/astrbot_sdk/testing.py
refactor(sdk): reorganize internals and harden runtime regressions
- Introduced new test suite for provider platform management in `test_sdk_provider_platform_management.py`, covering scenarios for merged provider configurations, reserved plugin checks, and provider management functionalities.
- Added tests for tool capabilities and provider queries in `test_sdk_provider_tool_platform_capabilities.py`, validating interactions with LLM tools and specialized proxies.
- Removed obsolete `test_sdk_transport.py` as it contained outdated tests for transport layer functionality.
添加多个模块和测试用例,增强SDK功能并支持单元测试
…metadata

Register methods for db, memory, http, and metadata capabilities exist in
BasicCapabilityMixin but were never called in CoreCapabilityBridge.__init__.
This caused SDK plugins using ctx.memory, ctx.db, ctx.http to fail with
"LookupError: capability not found".
添加知识库文档管理功能,包括文档上传、列表、获取、删除和刷新能力,更新相关的能力路由和协议模式
9724f6230 chore: refresh vendor snapshot [skip ci]
87dd4d31f Merge pull request AstrBotDevs#103 from united-pooh:dev
816732c52 Merge branch 'dev' of https://github.com/united-pooh/astrbot-sdk into dev
740f497fb feat: 引入线程安全机制,优化插件加载和组件实例化过程
1c2c451b9 Merge pull request AstrBotDevs#102 from united-pooh/docs/72
dad29d656 docs: 翻译预期外的英文注释
0688d335f Merge pull request AstrBotDevs#101 from united-pooh/fix-96-init-gitignore-template
b7b3e6bc5 feat: generate plugin gitignore during init
REVERT: 378257db7 chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 9724f6230147d6101cc4c6493d3d6b7b8e1d4f33
56943300b chore: refresh vendor snapshot [skip ci]
215e06572 Merge pull request AstrBotDevs#104 from united-pooh:dev
ea10d593d feat: 增强插件导入机制,支持命名空间和动态导入
REVERT: 9724f6230 chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 56943300b29038e57ab859d19d900e2e967a3a8a
0a9c86345 chore: refresh vendor snapshot [skip ci]
b5d9b934b Merge pull request AstrBotDevs#105 from united-pooh:dev
c07f04e63 feat: 更新多个客户端和模块,增强类型注解和文档说明
REVERT: 56943300b chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 0a9c86345ea2192154580d0ef054b72b99892b9e
- Added validation to ensure HTTP routes and handler capabilities belong to the current plugin namespace in the SDK.
- Updated tests to reflect changes in API registration routes, ensuring they include the plugin ID as a prefix.
- Introduced new error handling for invalid route and capability registrations.
- Refactored existing tests to accommodate the new route structure and added tests for new validation logic.
- Improved the structure of SDK record creation for better readability and maintainability.
SDK 装饰器层(decorators.py)为所有装饰器增加 callable 检查和参数归一化/校验,
防止插件作者传入非法类型后在运行时才崩溃。conversation.py 修复 ConversationState
反序列化兼容。events.py 新增 has_admin_permission() 别名。

runtime/loader.py 引入 MetaPathFinder 替代纯 builtin __import__ hook,
解决插件 import alias 泄漏到 sys.modules 的问题;新增 _restore_plugin_import_hook()
用于测试 teardown。runtime/peer.py 防止 stop() 并发重入、入站消息超限拒绝(8MB),
_handle_raw_message 不再向上抛异常。runtime/transport.py 所有读循环改为帧级容错:
单帧 ValueError/UnicodeDecodeError 只跳过该帧,不中断整个连接。runtime/supervisor.py
为 worker 初始化增加 60s 超时。

core/command_compatibility.py 将 build_cross_system_conflicts 从 O(n*m) 暴力比较
优化为前缀索引查找,大幅减少命令冲突检测耗时。

core/platform/astr_message_event.py 新增语义清晰的 LLM/发送状态 API
(set_default_llm_blocked/should_call_default_llm/mark_send_operation 等),
旧 call_llm/_has_send_oper 字段保留但标记为内部实现。

core/sdk_bridge/request_runtime.py 对所有 overlay/context 字典操作加
threading.RLock,消除并发调度时的竞态条件;close_request_overlay 拆为锁内原子移除
+ 锁外 event 回写两阶段。plugin_bridge.py 新增 _snapshot_records 系列方法统一
遍历入口、Windows 平台 MCP 进程终止改用 taskkill、调度 handler 后 finally 关闭 overlay
防泄漏。dispatch_engine.py 全面使用新的 event API 替代直接写字段。

runtime_store.py 新增 mutation_lock 和 snapshot 方法。tests 覆盖 dispatch engine、
loader 隔离、transport 帧容错、bridge runtime capabilities、MCP/provider tool、
native command、vnext author experience 等场景。
新增 _internal/sdk_logger.py 作为 SDK 唯一日志出口,通过 logger.patch()
注入 plugin_tag、short_levelname、版本号等上下文字段,替换 12 个模块中
原有的 from loguru import logger 和 loader.py 里的 stdlib logging。

- decorator_lifecycle/cli/context/peer/supervisor/transport/worker/session_waiter/star: 改为从 sdk_logger 导入
- handler_dispatcher: 含方法内延迟导入也一并迁移
- loader: 移除 _LOGGER (logging.getLogger),全部改用 loguru + {} 格式串
- test_sdk_plugin_config_bridge: caplog 改为 monkeypatch 适配 loguru
8186cd3ee chore: refresh vendor snapshot [skip ci]
6e6dfd238 Merge pull request AstrBotDevs#107 from united-pooh/dev
86274a7bc fix: 修正文档注释格式,去除多余空格
1931f606f feat: 增强 StdioTransport 的错误处理,添加对格式错误的处理逻辑和相应的单元测试
566401bc5 feat: Implement mutual TLS support for websocket server and client transports
cfb74da6e fix: 修正文档注释格式,清理多余的内容
de3677be1 refactor: 统一日志入口,引入 sdk_logger 集中管理 loguru patch
9dce3419f Merge pull request AstrBotDevs#106 from united-pooh:dev
22082ef8b feat: 增强能力描述符和插件导入机制,优化消息处理和错误管理
0789119d6 fix: 修复导入顺序,优化类型注解
REVERT: 0a9c86345 chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 8186cd3ee6c8afe876df62382cf3ddfff6063137
44b67256b chore: refresh vendor snapshot [skip ci]
920d69ce1 Merge pull request AstrBotDevs#108 from united-pooh/dev
e4d388ff2 feat: 添加多个装饰器错误处理函数,增强装饰器的错误上下文信息 fix: 修复 StdioTransport 中的异常处理逻辑,确保在读取过程中正确处理 ValueError fix: 更新 WorkerSession 初始化错误处理,提供更清晰的错误日志
REVERT: 8186cd3ee chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 44b67256b55da78053a3ff3160df8256189c7d5e
3cf8142fb chore: refresh vendor snapshot [skip ci]
ffe5fd101 Merge pull request AstrBotDevs#110 from united-pooh:dev
15f7adf4b refactor: update documentation and code references from v4 to astrbot-sdk
a75fe8903 feat: 增强 wrap_client_exception 函数的异常处理逻辑,确保重建异常时的正确返回
7553253ed Merge pull request AstrBotDevs#109 from united-pooh/dev
7167f6ccf feat: 添加错误处理包装函数,增强客户端异常处理能力
REVERT: 44b67256b chore: refresh vendor snapshot [skip ci]

git-subtree-dir: astrbot-sdk
git-subtree-split: 3cf8142fb3dde637755495d62e1a0525887e87cf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature:plugin The bug / feature is about AstrBot plugin system. size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants